/*
 * 2011 Runedev development team
 * http://lazygamerz.org
 *
 * This library is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Lesser Gereral Public Licence as published by the Free
 * Software Foundation; either version 3 of the Licence, or (at your opinion) any
 * later version.
 *
 * This library is distributed in the hope that it will be usefull, but WITHOUT ANY
 * WARRANTY; without even the implied warranty of merchantability or fitness for a
 * particular purpose. See the GNU Lesser General Public Licence for more details.
 *
 * You should have received a copy of the GNU Lesser General Public Licence along
 * with this library; if not, write to the Free Software Foundation, Inc., 59
 * Temple Place, Suite 330, Boston, Ma 02111-1307 USA.
 *
 * http://www.gnu.org/licenses/lgpl.html (English)
 * http://gugs.sindominio.net/gnu-gpl/lgpl-es.html (Espa�ol)
 *
 */
package org.lazygamerz.scripting.api;

import java.util.ArrayList;
import java.util.List;

import org.rsbot.bot.Bot;
import org.rsbot.script.Calculations;
import org.rsbot.script.internal.Deque;
import org.rsbot.script.util.Filter;
import org.rsbot.script.wrappers.RSArea;
import org.rsbot.script.wrappers.RSGroundItem;
import org.rsbot.script.wrappers.RSItem;
import org.rsbot.script.wrappers.RSItemTile;
import org.rsbot.script.wrappers.RSTile;

/**
 * items on the ground of the game.
 * @author Runedev Development Team - version 1.0
 */
public class GroundItem {

    public static final Filter<RSGroundItem> filter = new Filter<RSGroundItem>() {

        public boolean accept(final RSGroundItem item) {
            return true;
        }
    };

    public GroundItem() {
    }

    /**
     * Returns the first (but not the closest) item found in a square within
     * (range) away from you.
     *
     * @param amount    The maximum distance.
     * @return          The first ground item found; or null if none were found.
     */
    public RSItemTile getItem(int amount) {
        int pX = Bot.player.getMine().getLocation().getX();
        int pY = Bot.player.getMine().getLocation().getY();
        int minX = pX - amount;
        int minY = pY - amount;
        int maxX = pX + amount;
        int maxY = pY + amount;
        for (int x = minX; x < maxX; x++) {
            for (int y = minY; y < maxY; y++) {
                RSItemTile[] items = getItemsAt(x, y);
                if (items.length > 0) {
                    return items[0];
                }
            }
        }
        return null;
    }

    public RSItemTile[] getItemArray(int amount) {
        ArrayList<RSItemTile> temp = new ArrayList<RSItemTile>();
        int pX = Bot.player.getMine().getLocation().getX();
        int pY = Bot.player.getMine().getLocation().getY();
        int minX = pX - amount;
        int minY = pY - amount;
        int maxX = pX + amount;
        int maxY = pY + amount;
        for (int x = minX; x < maxX; x++) {
            for (int y = minY; y < maxY; y++) {
                RSItemTile[] items = getItemsAt(x, y);
                if (items.length > 0) {
                    temp.add(items[0]);
                }
            }
        }
        if (temp.isEmpty()) {
            return null;
        }
        RSItemTile[] array = new RSItemTile[temp.size()];
        for (int i = 0; i < temp.size(); i++) {
            array[i] = temp.get(i);
        }
        return array;
    }

    /**
     * Returns the first (but not the closest) item with a specified id in the
     * playable(visible) area.
     *
     * @param id    The ID of the item to look for.
     * @return      The first matching ground item found; or null if none were found.
     */
    public RSItemTile getItemByID(int id) {
        return getItemByID(52, new int[]{id});
    }

    /**
     * Returns the first (but not the closest) item with a specified id found in
     * a square within (range) away from you.
     *
     * @param amount     The maximum distance in tiles.
     * @param id        The ID of the item to look for.
     * @return          The first matching ground item found; or null if none
     *                  were found.
     */
    public RSItemTile getItemByID(int amount, int id) {
        return getItemByID(amount, new int[]{id});
    }

    /**
     * Returns the first (but not the closest) item with any of the specified
     * IDs in a square within (range) away from you.
     *
     * @param amount        The maximum distance.
     * @param ids           The IDs of the items to look for.
     * @return              The first matching ground item found; or null if
     *                      none were found.
     */
    public RSItemTile getItemByID(int amount, int[] ids) {
        int pX = Bot.player.getMine().getLocation().getX();
        int pY = Bot.player.getMine().getLocation().getY();
        int minX = pX - amount;
        int minY = pY - amount;
        int maxX = pX + amount;
        int maxY = pY + amount;
        for (int x = minX; x <= maxX; x++) {
            for (int y = minY; y <= maxY; y++) {
                RSItemTile[] items = getItemsAt(x, y);
                for (RSItemTile item : items) {
                    int iId = item.getItem().getID();
                    for (int id : ids) {
                        if (iId == id) {
                            return item;
                        }
                    }
                }
            }
        }
        return null;
    }

    /**
     * Returns the first (but not the closest) item with a specified id in the
     * playable(visible) area.
     *
     * @param ids       The IDs of the items to look for.
     * @return          The first matching ground item found; or null if none.
     */
    public RSItemTile getItemByID(int[] ids) {
        return getItemByID(52, ids);
    }

    /**
     * Returns all the ground items at a tile on the current plane.
     *
     * @param x     The x position of the tile in the world.
     * @param y     The y position of the tile in the world.
     * @return      An array of the ground items on the specified tile.
     */
    public RSItemTile[] getItemsAt(int x, int y) {
        if (!Bot.game.isLoggedIn()) {
            return new RSItemTile[0];
        }

        List<RSItemTile> list = new ArrayList<RSItemTile>();

        org.rsbot.client.HashTable itemNC = Bot.game.client().getRSItemHashTable();
        int id = x | y << 14 | Bot.game.client().getPlane() << 28;

        org.rsbot.client.NodeListCache itemNLC =
                (org.rsbot.client.NodeListCache) Calculations.findNodeByID(itemNC, id);

        if (itemNLC == null) {
            return new RSItemTile[0];
        }
        @SuppressWarnings("rawtypes")
        Deque itemNL = new Deque(itemNLC.getNodeList());
        for (org.rsbot.client.RSItem item = (org.rsbot.client.RSItem) itemNL.getHead(); item != null; item = (org.rsbot.client.RSItem) itemNL.getNext()) {
            list.add(new RSItemTile(x, y, new RSItem(item)));
        }

        return list.toArray(new RSItemTile[list.size()]);
    }

    /**
     * Returns all the ground items at a tile on the current plane.
     *
     * @param t     The tile.
     * @return      An array of the ground items on the specified tile.
     */
    public RSItemTile[] getItemsAt(RSTile t) {
        return getItemsAt(t.getX(), t.getY());
    }

    /**
     * Returns an RSItemTile representing the nearest item on the ground with an
     * ID that matches any of the IDS provided. Can return null. RSItemTile is a
     * subclass of RSTile.
     *
     * @param ids       The IDs to look for.
     * @return          RSItemTile of the nearest item with the an ID that
     *                  matches any in the array of IDs provided; or null if
     *                  no matching ground items were found.
     */
    public RSItemTile getNearestItemByID(int... ids) {
        int dist = 9999999;
        int pX = Bot.player.getMine().getLocation().getX();
        int pY = Bot.player.getMine().getLocation().getY();
        int minX = pX - 52;
        int minY = pY - 52;
        int maxX = pX + 52;
        int maxY = pY + 52;
        RSItemTile itm = null;
        for (int x = minX; x <= maxX; x++) {
            for (int y = minY; y <= maxY; y++) {
                RSItemTile[] items = getItemsAt(x, y);
                for (RSItemTile item : items) {
                    int iId = item.getItem().getID();
                    for (int id : ids) {
                        if (iId == id && Bot.calculate.distanceTo(item) < dist) {
                            dist = Bot.calculate.distanceTo(item);
                            itm = item;
                        }
                    }
                }
            }
        }
        return itm;
    }

    /**
     * Searches for an item on the ground within the specified area. New
     * getNearestItemByID
     *
     * @param search    The area to search in for ground items
     * @param ids       The items to search for by ID
     * @return
     * @author RSHelper
     */
    public RSItemTile getNearestItemInAreaByID(RSArea search, int... ids) {
        int dist = 9999999;
        RSTile[][] t = search.getTiles();
        RSItemTile itm = null;
        for (RSTile[] element : t) {
            for (int y = 0; y < element.length; y++) {
                RSItemTile[] items = getItemsAt(element[y]);
                for (RSItemTile item : items) {
                    int iId = item.getItem().getID();
                    for (int id : ids) {
                        if (iId == id && Bot.calculate.distanceTo(item) < dist) {
                            dist = Bot.calculate.distanceTo(item);
                            itm = item;
                        }
                    }
                }
            }
        }
        return itm;
    }

}
